package com.gitee.wsl.mathematics.geometry.shape

import com.gitee.wsl.math.Math.EPSILON
import com.gitee.wsl.math.Math.TAU
import com.gitee.wsl.unit.angle.AngleUnit
import com.gitee.wsl.unit.angle.ext.div
import com.gitee.wsl.unit.angle.ext.getPoint
import com.gitee.wsl.unit.angle.ext.plus
import com.gitee.wsl.unit.angle.toRadians
import kotlin.math.max
import kotlin.math.sqrt


open class Arc(
    override val circle: Circle,
    var startAngle: AngleUnit = 0.0f.toRadians(),
    var sweepAngle: AngleUnit = 0.0f.toRadians(),
    var linkCenter: Boolean = true
): CircleEntry {

    constructor(
        center: Point,
        radius: Float = 0.0f,
        startAngle: AngleUnit = 0.0f.toRadians(),
        sweepAngle: AngleUnit = 0.0f.toRadians(),
        linkCenter: Boolean = true
    ):this(Circle(center, radius),startAngle, sweepAngle, linkCenter)

    val center:Point get() = circle.position

    val radius:Float get() = circle.radius

    val endAngle: AngleUnit get() = startAngle + sweepAngle

    val halfAngle: AngleUnit get() = startAngle + sweepAngle / 2

    val startPoint:Point get() = startAngle.getPoint(center, radius )

    val endPoint:Point get() = endAngle.getPoint(center,radius)

}

fun Circle.createArc(startAngle: AngleUnit = 0.0f.toRadians(),
                     sweepAngle: AngleUnit = 0.0f.toRadians(),
                     linkCenter: Boolean = true) = Arc(this, startAngle, sweepAngle, linkCenter)

//private fun defaultPadRadius(arc: Arc, startAngle: Float, endAngle: Float, padAngle: Float): Float =
//    sqrt(arc.innerRadius * arc.innerRadius + arc.outerRadius * arc.outerRadius)


private data class Intersection(
    val x: Float,
    val y: Float,
)

private fun intersect(x0: Float, y0: Float, x1: Float, y1: Float, x2: Float, y2: Float, x3: Float, y3: Float): Intersection? {
    val x10 = x1 - x0
    val y10 = y1 - y0
    val x32 = x3 - x2
    val y32 = y3 - y2
    var t = y32 * x10 - x32 * y10
    if (t * t < EPSILON) return null
    t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t
    return Intersection(x0 + t * x10, y0 + t * y10)
}

private data class CornerTangents(
    val cx: Float,
    val cy: Float,
    val x01: Float,
    val y01: Float,
    val x11: Float,
    val y11: Float,
)

// Compute perpendicular offset line of length rc.
// http://mathworld.wolfram.com/Circle-LineIntersection.html
private fun cornerTangents(x0: Float, y0: Float, x1: Float, y1: Float, r1: Float, rc: Float, cw: Boolean): CornerTangents {
    val x01 = x0 - x1
    val y01 = y0 - y1
    val lo = (if (cw) rc else -rc) / sqrt(x01 * x01 + y01 * y01)
    val ox = lo * y01
    val oy = -lo * x01
    val x11 = x0 + ox
    val y11 = y0 + oy
    val x10 = x1 + ox
    val y10 = y1 + oy
    val x00 = (x11 + x10) / 2
    val y00 = (y11 + y10) / 2
    val dx = x10 - x11
    val dy = y10 - y11
    val d2 = dx * dx + dy * dy
    val r = r1 - rc
    val D = x11 * y10 - x10 * y11
    val d = (if (dy < 0) -1 else 1) * sqrt(max(0f, r * r * d2 - D * D))
    val cx0 = (D * dy - dx * d) / d2
    val cy0 = (-D * dx - dy * d) / d2
    val cx1 = (D * dy + dx * d) / d2
    val cy1 = (-D * dx + dy * d) / d2
    val dx0 = cx0 - x00
    val dy0 = cy0 - y00
    val dx1 = cx1 - x00
    val dy1 = cy1 - y00

    val useSecondPoint = dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1
    val cx = if (useSecondPoint) cx1 else cx0
    val cy = if (useSecondPoint) cy1 else cy0
    return CornerTangents(
        cx = cx,
        cy = cy,
        x01 = -ox,
        y01 = -oy,
        x11 = cx * (r1 / r - 1),
        y11 = cy * (r1 / r - 1),
    )
}

private fun Float.toDegrees(): Float = (this * 360 / TAU).toFloat()

private fun Float.normalizeDegrees(): Float {
    val remainder = this % 360
    return if (remainder < 0f) remainder + 360f else remainder
}
